<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
<!-- designer-manual.qdoc -->
  <title>在应用程序中使用UI文件 | Qt Designer 手册</title>
  <link rel="stylesheet" type="text/css" href="style/offline-simple.css" />
  <script type="text/javascript">
    document.getElementsByTagName("link").item(0).setAttribute("href", "style/offline.css");
    // loading style sheet breaks anchors that were jumped to before
    // so force jumping to anchor again
    setTimeout(function() {
        var anchor = location.hash;
        // need to jump to different anchor first (e.g. none)
        location.hash = "#";
        setTimeout(function() {
            location.hash = anchor;
        }, 0);
    }, 0);
  </script>
</head>
<body>
<div class="header" id="qtdocheader">
  <div class="main">
    <div class="main-rounded">
      <div class="navigationbar">
        <table><tr>
<td ><a href="../qtdoc/index.html">Qt 5.14</a></td><td ><a href="qtdesigner-manual.html">Qt Designer 手册</a></td><td >在应用程序中使用UI文件</td></tr></table><table class="buildversion"><tr>
<td id="buildversion" width="100%" align="right"><a href="qtdesigner-manual.html">Qt 5.14.2 参考文档</a></td>
        </tr></table>
      </div>
    </div>
<div class="content">
<div class="line">
<div class="content mainContent">
  <link rel="prev" href="designer-stylesheet.html" />
  <link rel="next" href="designer-using-custom-widgets.html" />
<p class="naviNextPrevious headerNavi">
<a class="prevPage" href="designer-stylesheet.html">使用样式</a>
<span class="naviSeparator">  &#9702;  </span>
<a class="nextPage" href="designer-using-custom-widgets.html">使用自定义小部件（Widgets）</a>
</p><p/>
<div class="sidebar">
<div class="toc">
<h3><a name="toc">目录</a></h3>
<ul>
<li class="level1"><a href="#compile-time-form-processing">编译时窗体处理</a></li>
<li class="level2"><a href="#the-direct-approach">直接法</a></li>
<li class="level2"><a href="#the-single-inheritance-approach">单继承法</a></li>
<li class="level2"><a href="#the-multiple-inheritance-approach">多继承法</a></li>
<li class="level2"><a href="#reacting-to-language-changes">对语言变化的反应</a></li>
<li class="level1"><a href="#run-time-form-processing">运行时窗体处理</a></li>
<li class="level2"><a href="#the-uitools-approach">UiTools方法</a></li>
<li class="level1"><a href="#automatic-connections">自动连接</a></li>
<li class="level2"><a href="#a-dialog-without-auto-connect">没有自动连接的对话框</a></li>
<li class="level2"><a href="#widgets-and-dialogs-with-auto-connect">带有自动连接的小部件和对话框</a></li>
</ul>
</div>
<div class="sidebar-content" id="sidebar-content"></div></div>
<h1 class="title">在应用程序中使用UI文件</h1>
<span class="subtitle"></span>
<!-- $$$designer-using-a-ui-file.html-description -->
<div class="descr"> <a name="details"></a>
<p>Qt Designer UI 文件以XML格式树表示窗体中的小部件。以下窗体可处理:</p>
<ul>
<li><a href="designer-using-a-ui-file.html#compile-time-form-processing">编译时</a>, 这意味着窗体被转换成可以编译的c++代码 。</li>
<li><a href="designer-using-a-ui-file.html#run-time-form-processing">运行时</a>, 这意味着窗体是由在解析XML文件时动态构造小部件树的 <a href="../qtuitools/quiloader.html">QUiLoader</a> 类处理的。</li>
</ul>
<a name="compile-time-form-processing"></a>
<h2 id="compile-time-form-processing">编译时窗体处理</h2>
<p>您可以使用 <i>Qt Designer</i> 创建用户界面组件，并使用Qt的集成构建工具 <a href="../qmake/qmake-manual.html">qmake</a> 和 <a href="../qtdoc/uic.html">uic</a> 在构建应用程序时为它们生成代码 。生成的代码包含窗体的用户界面对象 。它是一个 c++ 结构体，包含:</p>
<ul>
<li>指向窗体的小部件、布局、布局项、按钮组和操作的指针。</li>
<li>一个名为 <code>setupUi()</code> 的成员函数，用于在父部件上构建部件树。</li>
<li>一个名为 <code>retranslateUi()</code> 的成员函数，处理窗体字符串属性的转换。有关更多信息，请参见 <a href="designer-using-a-ui-file.html#reacting-to-language-changes">Reacting to Language Changes</a> 。</li>
</ul>
<p>生成的代码可以包含在应用程序中，并直接从应用程序中使用。或者，您可以使用它来扩展标准小部件的子类。</p>
<p>一个编译时处理的窗体可以下列一种方法应用在您的应用程序中:</p>
<ul>
<li><a href="designer-using-a-ui-file.html#the-direct-approach">直接法</a>: 您将构造一个小部件作为组件的占位符，并在其中设置用户界面。</li>
<li><a href="designer-using-a-ui-file.html#the-single-inheritance-approach">单继承法</a>: 子类化窗体的基类(例如 <a href="../qtwidgets/qwidget.html">QWidget</a> 或者 <a href="../qtwidgets/qdialog.html">QDialog</a> )，并包括窗体用户界面对象的私有实例。</li>
<li><a href="designer-using-a-ui-file.html#the-multiple-inheritance-approach">多继承法</a>: 将窗体的基类和窗体的用户接口对象都子类化。这允许从子类的范围内直接使用窗体中定义的小部件。</li>
</ul>
<p>为了演示，我们创建了一个简单的计算器窗体应用程序。它是基于原始 <a href="qtdesigner-calculatorform-example.html">计算器窗体</a> 的例子。</p>
<p>该应用程序由一个源文件 <code>main.cpp</code> 和一个UI文件组成。</p>
<p>用 <i>Qt Designer</i> 设计的 <code>calculatorform.ui</code> 文件如下图所示:</p>
<p class="centerAlign"><img src="images/directapproach-calculatorform.png" alt="" /></p><p>我们将使用 <code>qmake</code> 来构建可执行文件，所以我们需要写 <code>.pro</code> 文件:</p>
<pre class="cpp">

  HEADERS     = calculatorform.h

</pre>
<p>这个文件的特殊性是 <code>FORMS</code> 声明，告诉 <code>qmake</code> 用 <code>uic</code> 处理哪些文件。在本例中，是 <code>calculatorform.ui</code> 文件用于创建一个 <code>ui_calculatorform.h</code> 文件，该文件可被 <code>SOURCES</code> 声明中列出的任何文件使用。</p>
<p><b>注意:</b> 您可以使用 Qt Creator 创建计算器窗体项目。它自动生成main.cpp, UI, 和 .pro文件，然后可以修改这些文件。</p><a name="the-direct-approach"></a>
<h3 id="the-direct-approach">直接法</h3>
<p>为了使用直接法，我们直接在 <code>main.cpp</code> 中包含 <code>ui_calculatorform.h</code> 文件:</p>
<pre class="cpp">

  <span class="preprocessor">#include &quot;ui_calculatorform.h&quot;</span>

</pre>
<p><code>main</code> 函数通过构造一个标准 <a href="../qtwidgets/qwidget.html">QWidget</a> 来创建计算器小部件，用来托管由 <code>calculatorform.ui</code> 文件描述的用户界面。</p>
<pre class="cpp">

  <span class="type">int</span> main(<span class="type">int</span> argc<span class="operator">,</span> <span class="type">char</span> <span class="operator">*</span>argv<span class="operator">[</span><span class="operator">]</span>)
  {
      <span class="type"><a href="../qtwidgets/qapplication.html">QApplication</a></span> app(argc<span class="operator">,</span> argv);
      <span class="type"><a href="../qtwidgets/qwidget.html">QWidget</a></span> widget;
      Ui<span class="operator">::</span>CalculatorForm ui;
      ui<span class="operator">.</span>setupUi(<span class="operator">&amp;</span>widget);

      widget<span class="operator">.</span>show();
      <span class="keyword">return</span> app<span class="operator">.</span>exec();
  }

</pre>
<p>在本例中，<code>Ui::CalculatorForm</code> 是来自 <code>ui_calculatorform.h</code> 文件的接口描述对象，该文件设置了对话框的所有小部件及其信号和槽之间的连接。</p>
<p>直接法为在应用程序中使用简单的、自包含的组件提供了一种快速而简便的方法。但是，使用 <i>Qt Designer</i> 创建的组件通常需要与应用程序的其余代码紧密集成。例如，上面提供的 <code>CalculatorForm</code> 代码将编译并运行，但是 <a href="../qtwidgets/qspinbox.html">QSpinBox</a> 对象将不会与 <a href="../qtwidgets/qlabel.html">QLabel</a> 交互，因为我们需要一个自定义槽来执行添加操作并在 <a href="../qtwidgets/qlabel.html">QLabel</a> 中显示结果。要实现这一点，我们需要使用单继承法。</p>
<a name="the-single-inheritance-approach"></a>
<h3 id="the-single-inheritance-approach">单继承法</h3>
<p>为了使用单继承法，我们将一个标准Qt小部件子类化，并包括窗体用户界面对象的一个私有实例。这可以采取以下形式:</p>
<ul>
<li>成员变量</li>
<li>指针变量</li>
</ul>
<a name="using-a-member-variable"></a>
<h4 id="using-a-member-variable">使用成员变量</h4>
<p>在这种方法中，我们子类化一个 Qt widget，并从构造函数中设置用户界面。以这种方式使用的组件将窗体中使用的小部件和布局公开给 Qt widget 子类，并提供一个标准系统，用于在用户界面和应用程序中的其他对象之间建立信号和槽连接。生成的 <code>Ui::CalculatorForm</code> 结构是类的成员。</p>
<p>这种方法在 <a href="qtdesigner-calculatorform-example.html">计算器窗体</a> 示例中使用。</p>
<p>为了确保我们可以使用用户界面，我们需要包含 <code>uic</code> 生成的头文件，然后引用 <code>Ui::CalculatorForm</code> :</p>
<pre class="cpp">

  <span class="preprocessor">#include &quot;ui_calculatorform.h&quot;</span>

</pre>
<p>这意味着 <code>.pro</code> 文件必须包含 <code>calculatorform.h</code>文件:</p>
<pre class="cpp">

  HEADERS     = calculatorform.h

</pre>
<p>子类的定义方式如下:</p>
<pre class="cpp">

  <span class="keyword">class</span> CalculatorForm : <span class="keyword">public</span> <span class="type"><a href="../qtwidgets/qwidget.html">QWidget</a></span>
  {
      Q_OBJECT

  <span class="keyword">public</span>:
      <span class="keyword">explicit</span> CalculatorForm(<span class="type"><a href="../qtwidgets/qwidget.html">QWidget</a></span> <span class="operator">*</span>parent <span class="operator">=</span> nullptr);

  <span class="keyword">private</span> <span class="keyword">slots</span>:
      <span class="type">void</span> on_inputSpinBox1_valueChanged(<span class="type">int</span> value);
      <span class="type">void</span> on_inputSpinBox2_valueChanged(<span class="type">int</span> value);

  <span class="keyword">private</span>:
      Ui<span class="operator">::</span>CalculatorForm ui;
  };

</pre>
<p>类的重要特性是私有 <code>ui</code> 对象，它提供了用于设置和管理用户界面的代码。</p>
<p>子类的构造函数通过调用 <code>ui</code> 对象的 <code>setupUi()</code> 函数来构造和配置对话框的所有小部件和布局。完成此操作后，就可以根据需要修改用户界面。</p>
<pre class="cpp">

  CalculatorForm<span class="operator">::</span>CalculatorForm(<span class="type"><a href="../qtwidgets/qwidget.html">QWidget</a></span> <span class="operator">*</span>parent)
      : <span class="type"><a href="../qtwidgets/qwidget.html">QWidget</a></span>(parent)
  {
      ui<span class="operator">.</span>setupUi(<span class="keyword">this</span>);
  }

</pre>
<p>通过添加 on_&lt;object name&gt; -前缀，我们可以通常的方式连接用户界面小部件中的信号和槽。有关更多信息，请参见 <a href="designer-using-a-ui-file.html#widgets-and-dialogs-with-auto-connect">widgets-and-dialogs-with-auto-connect</a> 。</p>
<p>这种方法的优点是，它简单地使用了继承来提供基于 <a href="../qtwidgets/qwidget.html">QWidget</a> 的接口，并将用户界面小部件变量封装在 <code>ui</code> 数据成员中。我们可以使用这个方法在同一个小部件中定义许多用户界面，每个界面都包含在自己的名称空间中，并覆盖(或组合)它们。例如，这种方法可用于从现有窗体创建单独的选项卡。</p>
<a name="using-a-pointer-member-variable"></a>
<h4 id="using-a-pointer-member-variable">使用指针变量</h4>
<p>或者，<code>Ui::CalculatorForm</code> 结构可以为类的指针。开头看起来如下:</p>
<pre class="cpp">

  <span class="keyword">namespace</span> Ui {
      <span class="keyword">class</span> CalculatorForm;
  }

  <span class="keyword">class</span> CalculatorForm : <span class="keyword">public</span> <span class="type"><a href="../qtwidgets/qwidget.html">QWidget</a></span>
  <span class="operator">.</span><span class="operator">.</span><span class="operator">.</span>
  <span class="keyword">virtual</span> <span class="operator">~</span>CalculatorForm();
  <span class="operator">.</span><span class="operator">.</span><span class="operator">.</span>
  <span class="keyword">private</span>:
      Ui<span class="operator">::</span>CalculatorForm <span class="operator">*</span>ui;
  <span class="operator">.</span><span class="operator">.</span><span class="operator">.</span>

</pre>
<p>对应的源文件如下:</p>
<pre class="cpp">

  <span class="preprocessor">#include &quot;ui_calculatorform.h&quot;</span>

  CalculatorForm<span class="operator">::</span>CalculatorForm(<span class="type"><a href="../qtwidgets/qwidget.html">QWidget</a></span> <span class="operator">*</span>parent) :
      <span class="type"><a href="../qtwidgets/qwidget.html">QWidget</a></span>(parent)<span class="operator">,</span> ui(<span class="keyword">new</span> Ui<span class="operator">::</span>CalculatorForm)
  {
      ui<span class="operator">-</span><span class="operator">&gt;</span>setupUi(<span class="keyword">this</span>);
  }

  CalculatorForm<span class="operator">::</span><span class="operator">~</span>CalculatorForm()
  {
      <span class="keyword">delete</span> ui;
  }

</pre>
<p>这种方法的优点是用户界面对象可以预先声明，这意味着我们不必在头文件中包含生成的 <code>ui_calculatorform.h</code> 文件。然后可以在不重新编译相关源文件的情况下更改窗体。如果类受到二进制兼容性限制，这一点尤其重要。</p>
<p>我们通常推荐这种方法用于库和大型应用程序。有关更多信息，请参见 <a href="../qtdoc/sharedlibrary.html">创建共享库</a> 。</p>
<a name="the-multiple-inheritance-approach"></a>
<h3 id="the-multiple-inheritance-approach">多继承法</h3>
<p>使用 <i>Qt Designer</i> 创建的窗体可以与标准的基于 <a href="../qtwidgets/qwidget.html">QWidget</a> 的类一起子类化。这种方法可以在子类的范围内直接访问窗体中定义的所有用户界面组件，并允许使用 <a href="../qtcore/qobject.html#connect">connect()</a> 函数以通常的方式建立信号和槽连接。</p>
<p>此方法在 <a href="../qtuitools/qtuitools-multipleinheritance-example.html">多继承</a> 示例中使用。</p>
<p>我们需要包含 <code>uic</code> 根据 <code>calculatorform.ui</code> 文件生成的头文件，如下所示:</p>
<pre class="cpp">

  <span class="preprocessor">#include &quot;ui_calculatorform.h&quot;</span>

</pre>
<p>这个类的定义方式与 <a href="designer-using-a-ui-file.html#the-single-inheritance-approach">单继承法</a> 中的类似，除此以外，我们 <i>同时</i> 从 <a href="../qtwidgets/qwidget.html">QWidget</a> 和 <code>Ui::CalculatorForm</code> 继承了，如下所示:</p>
<pre class="cpp">

  <span class="keyword">class</span> CalculatorForm : <span class="keyword">public</span> <span class="type"><a href="../qtwidgets/qwidget.html">QWidget</a></span><span class="operator">,</span> <span class="keyword">private</span> Ui<span class="operator">::</span>CalculatorForm
  {
      Q_OBJECT

  <span class="keyword">public</span>:
      <span class="keyword">explicit</span> CalculatorForm(<span class="type"><a href="../qtwidgets/qwidget.html">QWidget</a></span> <span class="operator">*</span>parent <span class="operator">=</span> nullptr);

  <span class="keyword">private</span> <span class="keyword">slots</span>:
      <span class="type">void</span> on_inputSpinBox1_valueChanged(<span class="type">int</span> value);
      <span class="type">void</span> on_inputSpinBox2_valueChanged(<span class="type">int</span> value);
  };

</pre>
<p>私有继承了 <code>Ui::CalculatorForm</code> ，以确保用户界面对象在子类中是私有的。还可以 <code>public</code> 或 <code>protected</code> 继承，就像前面的例子中使 <code>ui</code> 为 public 或 protected 一样。</p>
<p>子类的构造函数执行许多与 <a href="designer-using-a-ui-file.html#the-single-inheritance-approach">单继承</a> 示例中使用的构造函数相同的任务:</p>
<pre class="cpp">

  CalculatorForm<span class="operator">::</span>CalculatorForm(<span class="type"><a href="../qtwidgets/qwidget.html">QWidget</a></span> <span class="operator">*</span>parent)
      : <span class="type"><a href="../qtwidgets/qwidget.html">QWidget</a></span>(parent)
  {
      setupUi(<span class="keyword">this</span>);
  }

</pre>
<p>在这种情况下，用户界面中使用的小部件可以用与手工在代码中创建的小部件相同的方式访问。
我们不再需要 <code>ui</code> 前缀来访问它们。</p>
<a name="reacting-to-language-changes"></a>
<h3 id="reacting-to-language-changes">对语言变化的反应</h3>
<p>Qt 通过发送一个类型为 <a href="../qtcore/qevent.html#Type-enum">QEvent::LanguageChange</a> 的事件来通知应用程序，如果用户界面语言发生变化。
为了调用用户接口对象的成员函数 <code>retranslateUi()</code> ，我们在窗体类中重新实现 <code>QWidget::changeEvent()</code> ，如下所示:</p>
<pre class="cpp">

  <span class="type">void</span> CalculatorForm<span class="operator">::</span>changeEvent(<span class="type"><a href="../qtcore/qevent.html">QEvent</a></span> <span class="operator">*</span>e)
  {
      <span class="type"><a href="../qtwidgets/qwidget.html">QWidget</a></span><span class="operator">::</span>changeEvent(e);
      <span class="keyword">switch</span> (e<span class="operator">-</span><span class="operator">&gt;</span>type()) {
      <span class="keyword">case</span> <span class="type"><a href="../qtcore/qevent.html">QEvent</a></span><span class="operator">::</span>LanguageChange:
          ui<span class="operator">-</span><span class="operator">&gt;</span>retranslateUi(<span class="keyword">this</span>);
          <span class="keyword">break</span>;
      <span class="keyword">default</span>:
          <span class="keyword">break</span>;
     }
  }

</pre>
<a name="run-time-form-processing"></a>
<h2 id="run-time-form-processing">运行时窗体处理</h2>
<p>或者，可以在运行时处理窗体，产生动态生成的用户界面。
这可以使用 <a href="../qtuitools/qtuitools-module.html">QtUiTools</a> 模块来完成，该模块提供了 <a href="../qtuitools/quiloader.html">QUiLoader</a> 类来处理用 <i>Qt Designer</i> 创建的窗体 。</p>
<a name="the-uitools-approach"></a>
<h3 id="the-uitools-approach">UiTools方法</h3>
<p>在运行时，需要一个包含UI文件的资源文件来处理窗体 。
此外，还需要将应用程序配置为使用 <a href="../qtuitools/qtuitools-module.html">QtUiTools</a> 模块。
这是通过在 <code>qmake</code> 项目文件中包含以下声明来实现的，确保适当地编译和链接应用程序。</p>
<pre class="cpp">

  QT += uitools

</pre>
<p><a href="../qtuitools/quiloader.html">QUiLoader</a> 类提供了一个窗体加载器对象来构造用户界面。
这个用户界面可以从任何 <a href="../qtcore/qiodevice.html">QIODevice</a> (例如 <a href="../qtcore/qfile.html">QFile</a> 对象)中检索，以获取存储在项目资源文件中的窗体 。
<a href="../qtuitools/quiloader.html#load">QUiLoader::load</a>() 函数使用文件中包含的用户界面描述构造窗体小部件。</p>
<p><a href="../qtuitools/qtuitools-module.html">QtUiTools</a> 模块类可以使用以下指令包含:</p>
<pre class="cpp">

  <span class="preprocessor">#include &lt;QtUiTools&gt;</span>

</pre>
<p>从 <a href="../qtuitools/qtuitools-textfinder-example.html">文本查找器（Text Finder）</a> 示例调用 <a href="../qtuitools/quiloader.html#load">QUiLoader::load</a>() 函数，如下代码所示:</p>
<pre class="cpp">

  <span class="keyword">static</span> <span class="type"><a href="../qtwidgets/qwidget.html">QWidget</a></span> <span class="operator">*</span>loadUiFile(<span class="type"><a href="../qtwidgets/qwidget.html">QWidget</a></span> <span class="operator">*</span>parent)
  {
      <span class="type"><a href="../qtcore/qfile.html">QFile</a></span> file(<span class="string">&quot;:/forms/textfinder.ui&quot;</span>);
      file<span class="operator">.</span>open(<span class="type"><a href="../qtcore/qiodevice.html">QIODevice</a></span><span class="operator">::</span>ReadOnly);

      <span class="type"><a href="../qtuitools/quiloader.html">QUiLoader</a></span> loader;
      <span class="keyword">return</span> loader<span class="operator">.</span>load(<span class="operator">&amp;</span>file<span class="operator">,</span> parent);
  }

</pre>
<p>在使用 <a href="../qtuitools/qtuitools-module.html">QtUiTools</a> 在运行时构建其用户界面的类中，我们可以使用 <a href="../qtcore/qobject.html#findChild">QObject::findChild</a>() 定位窗体中的对象。
例如，在下面的代码中，我们根据对象名称和部件类型定位一些组件:</p>
<pre class="cpp">

      ui_findButton <span class="operator">=</span> findChild<span class="operator">&lt;</span><span class="type"><a href="../qtwidgets/qpushbutton.html">QPushButton</a></span><span class="operator">*</span><span class="operator">&gt;</span>(<span class="string">&quot;findButton&quot;</span>);
      ui_textEdit <span class="operator">=</span> findChild<span class="operator">&lt;</span><span class="type"><a href="../qtwidgets/qtextedit.html">QTextEdit</a></span><span class="operator">*</span><span class="operator">&gt;</span>(<span class="string">&quot;textEdit&quot;</span>);
      ui_lineEdit <span class="operator">=</span> findChild<span class="operator">&lt;</span><span class="type"><a href="../qtwidgets/qlineedit.html">QLineEdit</a></span><span class="operator">*</span><span class="operator">&gt;</span>(<span class="string">&quot;lineEdit&quot;</span>);

</pre>
<p>在运行时处理窗体使开发人员可以通过更改UI文件自由地更改程序的用户界面。
这在自定义程序以满足各种用户需求时非常有用，例如超大图标或用于辅助功能支持的不同颜色方案 。</p>
<a name="automatic-connections"></a>
<h2 id="automatic-connections">自动连接</h2>
<p>为编译时或运行时窗体定义的信号和槽连接可以手动或自动设置，使用 <a href="../qtcore/qmetaobject.html">QMetaObject</a> 的功能在信号和合适命名的槽之间建立连接。</p>
<p>通常，在 <a href="../qtwidgets/qdialog.html">QDialog</a> 中，如果我们想在接受用户输入的信息之前处理它，我们需要将 clicked() 信号从 <b>OK</b> 按钮连接到对话框中的自定义槽。
我们将首先展示一个手动连接槽的对话框示例，然后将其与使用自动连接的对话框进行比较。</p>
<a name="a-dialog-without-auto-connect"></a>
<h3 id="a-dialog-without-auto-connect">没有自动连接的对话框</h3>
<p>我们用和以前一样的方式定义对话框，但是现在除了构造函数外还包括了一个槽:</p>
<pre class="cpp">

  <span class="keyword">class</span> ImageDialog : <span class="keyword">public</span> <span class="type"><a href="../qtwidgets/qdialog.html">QDialog</a></span><span class="operator">,</span> <span class="keyword">private</span> Ui<span class="operator">::</span>ImageDialog
  {
      Q_OBJECT

  <span class="keyword">public</span>:
      ImageDialog(<span class="type"><a href="../qtwidgets/qwidget.html">QWidget</a></span> <span class="operator">*</span>parent <span class="operator">=</span> <span class="number">0</span>);

  <span class="keyword">private</span> <span class="keyword">slots</span>:
      <span class="type">void</span> checkValues();
  };

</pre>
<p><code>checkValues()</code> 槽将用于验证用户提供的值。</p>
<p>在对话框的构造函数中，我们像前面一样设置了小部件，并将 <b>Cancel</b> 按钮的 <a href="../qtwidgets/qabstractbutton.html#clicked">clicked()</a> 信号连接到对话框的 reject() 槽。
我们还禁用了这两个按钮的 <a href="../qtwidgets/qpushbutton.html#autoDefault-prop">autoDefault</a> 属性，以确保对话框不会因为 line edit 的回车键事件触发的干扰 :</p>
<pre class="cpp">

  ImageDialog<span class="operator">::</span>ImageDialog(<span class="type"><a href="../qtwidgets/qwidget.html">QWidget</a></span> <span class="operator">*</span>parent)
      : <span class="type"><a href="../qtwidgets/qdialog.html">QDialog</a></span>(parent)
  {
      setupUi(<span class="keyword">this</span>);
      okButton<span class="operator">-</span><span class="operator">&gt;</span>setAutoDefault(<span class="keyword">false</span>);
      cancelButton<span class="operator">-</span><span class="operator">&gt;</span>setAutoDefault(<span class="keyword">false</span>);
      ...
      connect(okButton<span class="operator">,</span> SIGNAL(clicked())<span class="operator">,</span> <span class="keyword">this</span><span class="operator">,</span> SLOT(checkValues()));
  }

</pre>
<p>我们将 <b>OK</b> 按钮的 <a href="../qtwidgets/qabstractbutton.html#clicked">clicked()</a> 信号连接到对话框的 checkValues() 槽，实现如下:</p>
<pre class="cpp">

  <span class="type">void</span> ImageDialog<span class="operator">::</span>checkValues()
  {
      <span class="keyword">if</span> (nameLineEdit<span class="operator">-</span><span class="operator">&gt;</span>text()<span class="operator">.</span>isEmpty())
          (<span class="type">void</span>) <span class="type"><a href="../qtwidgets/qmessagebox.html">QMessageBox</a></span><span class="operator">::</span>information(<span class="keyword">this</span><span class="operator">,</span> tr(<span class="string">&quot;No Image Name&quot;</span>)<span class="operator">,</span>
              tr(<span class="string">&quot;Please supply a name for the image.&quot;</span>)<span class="operator">,</span> <span class="type"><a href="../qtwidgets/qmessagebox.html">QMessageBox</a></span><span class="operator">::</span>Cancel);
      <span class="keyword">else</span>
          accept();
  }

</pre>
<p>这个自定义槽做了确保用户输入的数据是有效的所必需的最小工作—它只接受为 image 指定了名称的输入。</p>
<a name="widgets-and-dialogs-with-auto-connect"></a>
<h3 id="widgets-and-dialogs-with-auto-connect">带有自动连接的小部件和对话框</h3>
<p>尽管在对话框中实现自定义槽并在构造函数中连接它很容易，但我们可以使用 <a href="../qtcore/qmetaobject.html">QMetaObject</a> 的自动连接工具将 <b>OK</b> 按钮的 clicked() 信号连接到子类中的槽。
<code>uic</code> 自动在对话框的 <code>setupUi()</code> 函数中生成代码来完成此操作，因此我们只需要声明和实现一个槽，其名称遵循标准约定:</p>
<pre class="cpp">

  <span class="type">void</span> on_<span class="operator">&lt;</span>object name<span class="operator">&gt;</span>_<span class="operator">&lt;</span>signal name<span class="operator">&gt;</span>(<span class="operator">&lt;</span>signal parameters<span class="operator">&gt;</span>);

</pre>
<p>使用这个约定，我们可以定义和实现一个响应鼠标点击 <b>OK</b> 按钮的槽:</p>
<pre class="cpp">

  <span class="keyword">class</span> ImageDialog : <span class="keyword">public</span> <span class="type"><a href="../qtwidgets/qdialog.html">QDialog</a></span><span class="operator">,</span> <span class="keyword">private</span> Ui<span class="operator">::</span>ImageDialog
  {
      Q_OBJECT

  <span class="keyword">public</span>:
      ImageDialog(<span class="type"><a href="../qtwidgets/qwidget.html">QWidget</a></span> <span class="operator">*</span>parent <span class="operator">=</span> <span class="number">0</span>);

  <span class="keyword">private</span> <span class="keyword">slots</span>:
      <span class="type">void</span> on_okButton_clicked();
  };

</pre>
<p>自动信号和槽连接的另一个例子是 <a href="../qtuitools/qtuitools-textfinder-example.html">文本查找器（Text Finder）</a> 及其 <code>on_findButton_clicked()</code> 槽 。</p>
<p>我们使用 <a href="../qtcore/qmetaobject.html">QMetaObject</a> 的系统来启用信号和槽连接:</p>
<pre class="cpp">

      <span class="type"><a href="../qtcore/qmetaobject.html">QMetaObject</a></span><span class="operator">::</span>connectSlotsByName(<span class="keyword">this</span>);

</pre>
<p>这使我们能够实现槽，如下所示:</p>
<pre class="cpp">

  <span class="type">void</span> TextFinder<span class="operator">::</span>on_findButton_clicked()
  {
      <span class="type"><a href="../qtcore/qstring.html">QString</a></span> searchString <span class="operator">=</span> ui_lineEdit<span class="operator">-</span><span class="operator">&gt;</span>text();
      <span class="type">QTextDocument</span> <span class="operator">*</span>document <span class="operator">=</span> ui_textEdit<span class="operator">-</span><span class="operator">&gt;</span>document();

      bool found <span class="operator">=</span> <span class="keyword">false</span>;

      <span class="comment">// undo previous change (if any)</span>
      document<span class="operator">-</span><span class="operator">&gt;</span>undo();

      <span class="keyword">if</span> (searchString<span class="operator">.</span>isEmpty()) {
          <span class="type"><a href="../qtwidgets/qmessagebox.html">QMessageBox</a></span><span class="operator">::</span>information(<span class="keyword">this</span><span class="operator">,</span> tr(<span class="string">&quot;Empty Search Field&quot;</span>)<span class="operator">,</span>
                                   tr(<span class="string">&quot;The search field is empty. &quot;</span>
                                      <span class="string">&quot;Please enter a word and click Find.&quot;</span>));
      } <span class="keyword">else</span> {
          <span class="type">QTextCursor</span> highlightCursor(document);
          <span class="type">QTextCursor</span> cursor(document);

          cursor<span class="operator">.</span>beginEditBlock();
      ...
          cursor<span class="operator">.</span>endEditBlock();

          <span class="keyword">if</span> (found <span class="operator">=</span><span class="operator">=</span> <span class="keyword">false</span>) {
              <span class="type"><a href="../qtwidgets/qmessagebox.html">QMessageBox</a></span><span class="operator">::</span>information(<span class="keyword">this</span><span class="operator">,</span> tr(<span class="string">&quot;Word Not Found&quot;</span>)<span class="operator">,</span>
                                       tr(<span class="string">&quot;Sorry, the word cannot be found.&quot;</span>));
          }
      }
  }

</pre>
<p>信号和槽的自动连接为小部件设计人员提供了标准的命名约定和显式接口。
通过提供实现给定界面的源代码，用户界面设计人员无需自己编写代码就可以检查他们的设计是否真正有效。</p>
</div>
<!-- @@@designer-using-a-ui-file.html -->
<p class="naviNextPrevious footerNavi">
<a class="prevPage" href="designer-stylesheet.html">使用样式</a>
<span class="naviSeparator">  &#9702;  </span>
<a class="nextPage" href="designer-using-custom-widgets.html">使用自定义小部件（Widgets）</a>
</p>
        </div>
       </div>
   </div>
   </div>
</div>
<div class="footer">
   <p>
   <acronym title="Copyright">&copy;</acronym> 2020 The Qt Company Ltd. 文档贡献包括在这里是各自所有者的版权。<br /> 在此提供的文档是根据由自由软件基金会发布的<a href="http://www.gnu.org/licenses/fdl.html">GNU Free Documentation License version 1.3</a>的条款授权的。<br /> Qt及其商标为Qt有限公司的商标。在芬兰和/或世界其他国家。所有其他商标均为其各自所有者的财产。 </p>
</div>
</body>
</html>
